import { useEffect, useRef, useState } from 'react'
import useObject from './useObject'
import { getWebSocketUrl, toBase64 } from './utils'

export const STATUS = {
  UNDEFINED: 'UNDEFINED',
  CONNECTING: 'CONNECTING',
  OPEN: 'OPEN',
  CLOSING: 'CLOSING',
  CLOSED: 'CLOSED',
} as const
export type StatusType = (typeof STATUS)[keyof typeof STATUS]

export type UseXFVoiceOptions = {
  onRecordEnd?: (text: string) => void
  onError?: (error: Error) => void
}

export const useXFVoice = function (options?: UseXFVoiceOptions) {
  const { onRecordEnd, onError } = { ...options }
  const [recStatus, setRecStatus] = useState<StatusType>(STATUS.UNDEFINED)
  const [recText, setRecText] = useState('')
  const [recSec, setRecSec] = useState(0)
  const iatWS = useRef<WebSocket | null>(null)
  const recordTextRef = useRef({
    text: '',
    temp: '',
    rs: '',
  })
  const recorder = useObject(() => new window.RecorderManager('/xf/build'))

  const countdownInterval = useRef(0)

  function countdown() {
    const seconds = 60
    setRecSec(60)
    countdownInterval.current = window.setInterval(() => {
      if (seconds <= 0) {
        window.clearInterval(countdownInterval.current)
        recorder.stop()
      }
      else {
        setRecSec(seconds - 1)
      }
    }, 1000)
  }

  function changeBtnStatus(status: StatusType) {
    setRecStatus(status)
    if (status === STATUS.CONNECTING) {
      recordTextRef.current.text = ''
      recordTextRef.current.temp = ''
      recordTextRef.current.rs = ''
      setRecText('')
    }
    else if (status === STATUS.OPEN) {
      countdown()
    }
  }

  function renderResult(resultData: string) {
    let resultText = recordTextRef.current.text
    let resultTextTemp = recordTextRef.current.temp
    // 识别结束
    const jsonData = JSON.parse(resultData)
    if (jsonData.data && jsonData.data.result) {
      const data = jsonData.data.result
      let str = ''
      const ws = data.ws
      for (let i = 0; i < ws.length; i++)
        str = str + ws[i].cw[0].w

      // 开启wpgs会有此字段(前提：在控制台开通动态修正功能)
      // 取值为 "apd"时表示该片结果是追加到前面的最终结果；取值为"rpl" 时表示替换前面的部分结果，替换范围为rg字段
      if (data.pgs) {
        if (data.pgs === 'apd') {
          // 将resultTextTemp同步给resultText
          resultText = resultTextTemp
        }
        // 将结果存储在resultTextTemp中
        resultTextTemp = resultText + str
      }
      else {
        resultText = resultText + str
      }
      console.log('VR:', resultTextTemp || resultText || '')
      const recordRs = resultTextTemp || resultText || ''
      recordTextRef.current.text = resultText
      recordTextRef.current.temp = resultTextTemp
      recordTextRef.current.rs = recordRs
      setRecText(recordRs)
    }
    if (jsonData.code === 0 && jsonData.data.status === 2) {
      onRecordEnd?.(recordTextRef.current.rs)
      iatWS.current!.close()
    }

    if (jsonData.code !== 0) {
      iatWS.current!.close()
      console.error(jsonData)
    }
  }

  function connectWebSocket() {
    const websocketUrl = getWebSocketUrl()
    const ws = new WebSocket(websocketUrl)
    iatWS.current = ws
    changeBtnStatus(STATUS.CONNECTING)
    ws.onopen = async () => {
      try {
        // 开始录音

        await recorder.start({
          sampleRate: 16000,
          frameSize: 1280,
          onError: (e) => {
            onError?.(e)
          },
        })
        const params = {
          common: {
            app_id: APPID,
          },
          business: {
            language: 'zh_cn',
            domain: 'iat',
            accent: 'mandarin',
            vad_eos: 5000,
            dwa: 'wpgs',
          },
          data: {
            status: 0,
            format: 'audio/L16;rate=16000',
            encoding: 'raw',
          },
        }
        ws.send(JSON.stringify(params))
      }
      catch (e) {
        console.error(e)
        onError?.(e)
      }
    }
    ws.onmessage = (e) => {
      console.log(e)
      renderResult(e.data)
    }
    ws.onerror = (e) => {
      console.error(e)
      recorder.stop()
      changeBtnStatus(STATUS.CLOSED)
    }
    ws.onclose = () => {
      recorder.stop()
      changeBtnStatus(STATUS.CLOSED)
    }
  }

  useEffect(() => {
    recorder.onStart = () => {
      changeBtnStatus(STATUS.OPEN)
    }
    recorder.onFrameRecorded = ({
      isLastFrame,
      frameBuffer,
    }: {
      isLastFrame: boolean
      frameBuffer: any
    }) => {
      if (iatWS.current!.readyState === WebSocket.OPEN) {
        iatWS.current!.send(
          JSON.stringify({
            data: {
              status: isLastFrame ? 2 : 1,
              format: 'audio/L16;rate=16000',
              encoding: 'raw',
              audio: toBase64(frameBuffer),
            },
          }),
        )
        if (isLastFrame)
          changeBtnStatus(STATUS.CLOSING)
      }
    }
    recorder.onStop = () => {
      clearInterval(countdownInterval.current)
    }
    return () => {
      clearInterval(countdownInterval.current)
    }
  }, [])

  const triggerRecord = () => {
    if (!window.isSecureContext) {
      onError?.(new Error('当前环境不支持语音输入'))
      return
    }
    if (recStatus === STATUS.UNDEFINED || recStatus === STATUS.CLOSED) {
      connectWebSocket()
    }
    else if (recStatus === STATUS.CONNECTING || recStatus === STATUS.OPEN) {
      // 结束录音
      recorder.stop()
    }
  }

  return {
    triggerRecord,
    recStatus,
    recText,
    recSec,
    isRecording: () => recStatus === STATUS.OPEN,
  }
}
